using Newtonsoft.Json;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Xml.Serialization;
using System.Web.Script.Serialization;

namespace DJY.Domain.ViewModel
{
    /// <summary>
    /// 节点属性
    /// </summary>
    public class WorkFlowNodeProperty
    {
        /// <summary>
        /// 节点Id
        /// </summary>
        /// <value></value>
        public string nodeId { get; set; }

        /// <summary>
        /// 属性名称（中文描述）
        /// </summary>
        /// <value></value>
        public string name{get;set;}

        /// <summary>
        /// 属性键
        /// </summary>
        /// <value></value>
        public string key{get;set;}

        /// <summary>
        /// 属性值
        /// </summary>
        /// <value></value>
        public string value{get;set;}

        /// <summary>
        /// 类型：0属性，1数据（节点间的数据会合并，属性不会）
        /// </summary>
        public byte type { get; set; }

        /// <summary>
        /// 真实值，减少转换用的
        /// </summary>
        /// <value></value>
        [JsonIgnore]
        [XmlIgnore]
        [ScriptIgnore]
        public object raw { get; set; }

        /// <summary>
        /// 转换为目标对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T ConvertTo<T>(IEnumerable<WorkFlowNodeProperty> props) where T:class,new()
        {
            T result = new T();
            if (props == null)
            {
                return result;
            }

            Type type = typeof(T);

            foreach (WorkFlowNodeProperty prop in props)
            {
                if(prop.value == null)
                {
                    continue;
                }

                PropertyInfo propInfo = type.GetProperty(prop.key, BindingFlags.Public
                    | BindingFlags.Instance
                    | BindingFlags.GetProperty
                    | BindingFlags.SetProperty
                    | BindingFlags.IgnoreCase);

                if(propInfo == null)
                {
                    continue;
                }

                object val = null;
                if (prop.raw != null)
                {
                    val = prop.raw;
                    propInfo.SetValue(result, val);
                }
                else
                {
                    if (propInfo.PropertyType.IsGenericType)
                    {
                        if (propInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        {
                            val = Convert.ChangeType(prop.value, propInfo.PropertyType.GetGenericArguments()[0]);
                            propInfo.SetValue(result, val);
                        }
                        else
                        {
                            val = JsonConvert.DeserializeObject(prop.value, propInfo.PropertyType);
                            propInfo.SetValue(result, val);
                        }
                    }
                    else
                    {
                        val = Convert.ChangeType(prop.value, propInfo.PropertyType);
                        propInfo.SetValue(result, val);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 转换为条件表达式字典
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="props">属性列表</param>
        /// <param name="dic">字典</param>
        /// <param name="modelType">模型类型</param>
        public static void ConvertTo(IEnumerable<WorkFlowNodeProperty> props, 
            IDictionary<string, object> dic,Type modelType)
        {
            if (props == null || dic == null)
                throw new ArgumentNullException();

            foreach(WorkFlowNodeProperty prop in props)
            {
                if (string.IsNullOrWhiteSpace(prop.key))
                {
                    continue;
                }

                if (prop.value == null || modelType == null || prop.raw != null)
                {
                    dic[prop.key] = prop.value;
                    continue;
                }

                PropertyInfo propInfo = modelType.GetProperty(prop.key, BindingFlags.Public
                    | BindingFlags.Instance
                    | BindingFlags.GetProperty
                    | BindingFlags.SetProperty
                    | BindingFlags.IgnoreCase);

                if (propInfo == null)
                {
                    dic[prop.key] = prop.value;
                    continue;
                }

                object val = null;
                if (propInfo.PropertyType.IsGenericType)
                {
                    if (propInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        val = Convert.ChangeType(prop.value, propInfo.PropertyType.GetGenericArguments()[0]);
                        dic[prop.key] = val;
                    }
                    else
                    {
                        val = JsonConvert.DeserializeObject(prop.value, propInfo.PropertyType);
                        dic[prop.key] = val;
                    }
                }
                else
                {
                    val = Convert.ChangeType(prop.value, propInfo.PropertyType);
                    dic[prop.key] = val;
                }
            }
        }

        /// <summary>
        /// 合并
        /// </summary>
        /// <param name="result">结果</param>
        /// <param name="source">需要合并的集合</param>
        public static void MergePropertyList(List<WorkFlowNodeProperty> result,List<WorkFlowNodeProperty> source)
        {
            if (result == null)
                throw new ArgumentNullException(nameof(result));

            if(source == null || source.Count == 0)
            {
                return;
            }

            source.ForEach(p=> {
                if (string.IsNullOrWhiteSpace(p.key))
                {
                    return;
                }

                WorkFlowNodeProperty prop = result.FirstOrDefault(sp => sp.type == p.type && sp.key == p.key);
                if (prop == null)
                {
                    result.Add(p);
                }
                else
                {
                    if(string.IsNullOrEmpty(prop.name) && !string.IsNullOrEmpty(p.name))
                    {
                        prop.name = p.name;
                    }
                    prop.value = p.value;
                }
            });
        }
    }
}